/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-12-24     sundm75       the first version
 */
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <stdlib.h>
#include "littlebeep.h"

#define DBG_TAG                 "pkg.littlebeep"
#ifdef PKG_USING_LITTLEBEEP_DEBUG
#define DBG_LVL                  DBG_LOG
#else
#define DBG_LVL                  DBG_ERROR
#endif
#include <rtdbg.h>

enum Beep_State
{
    BEEP_NONE            = 0,
    BEEP_START           = 1,
    BEEP_ON              = 2,
    BEEP_OFF             = 3,
    BEEP_END             = 4
};

struct beep_struct
{
    rt_base_t active_logic;
    rt_base_t pin;
    rt_uint32_t count;
    rt_uint32_t pulse;
    rt_uint32_t npulse;
};
static struct beep_struct beep_data = {0};
static rt_thread_t beep_thread = RT_NULL;
static int beep_state = BEEP_NONE;

static int beep_config(void)
{
    rt_pin_mode(DEFAULT_PIN, PIN_MODE_OUTPUT);
    beep_data.active_logic = DEFAULT_ACTIVELOGIC;
    beep_data.pin = DEFAULT_PIN;
    beep_data.count = DEFAULT_COUNT;
    beep_data.pulse = DEFAULT_PERIOD * DEFAULT_PERCENT/100;
    beep_data.npulse = DEFAULT_PERIOD - beep_data.pulse;
    beep_state = BEEP_START;
}

static void beep_on(void)
{
    rt_pin_write(beep_data.pin, beep_data.active_logic);
}

static void beep_off(void)
{
    rt_pin_write(beep_data.pin, !beep_data.active_logic);
}

void beep_mode(rt_uint32_t count, rt_uint32_t period, rt_uint32_t percent)
{
    if (count)
    {
        beep_data.count = count ;
        beep_data.pulse = period * percent / 100;
        beep_data.npulse = period - beep_data.pulse;
        beep_state = BEEP_START;
        LOG_D("beep start on");
    }
}

static void beep_task_entry(void *args)
{
    static rt_uint32_t ms_time_counter = 0;
    beep_config();

    while(1)
    {

        switch (beep_state)
        {
        case BEEP_NONE:
            break;
        case BEEP_START:
            if(beep_data.count--)
            {
                ms_time_counter = beep_data.pulse;
                beep_state = BEEP_ON;
            }
            else
            {
                beep_state = BEEP_END;
                ms_time_counter = 0;
                LOG_D("beep end");
            }
            break;
        case BEEP_ON:
            if (ms_time_counter --)
                beep_on();
            else
            {
                beep_state = BEEP_OFF;
                ms_time_counter = beep_data.npulse;
            }
            break;
        case BEEP_OFF:
            if (ms_time_counter --)
                beep_off();
            else
            {
                beep_state = BEEP_START;
            }
            break;
        case BEEP_END:
            beep_state = BEEP_NONE;
            break;
        default:
            break;
        }
        rt_thread_delay(1);
    }
}

static int litterbeep_init(void)
{
    if (beep_thread)
    {
        LOG_D("beep_thread has been created");
        return -RT_ERROR;
    }

    /* create the littled daemon thread */
    beep_thread = rt_thread_create("litterbeep", beep_task_entry, RT_NULL,
                                      1024, RT_THREAD_PRIORITY_MAX / 2, 20);
    if (beep_thread == RT_NULL)
        goto __exit;

    rt_thread_startup(beep_thread);
    LOG_D("beep_thread startup");
    return RT_EOK;

__exit:
    return -RT_ERROR;
}

#ifdef PKG_USING_LITTLEBEEP
INIT_APP_EXPORT(litterbeep_init);
#endif

static void beep(rt_uint8_t argc, char **argv)
{
    int count, period, prcent;

    if (argc <= 2)
    {
        rt_kprintf("Please input: beep <count> <period> [prcent] \n");
    }
    else if (argc == 3)
    {
        count = atoi(argv[1]);
        period = atoi(argv[2]);
        if (count > 0 && period >= 0 && period <= 1000)
            beep_mode(count, period, 50);
        else
            rt_kprintf("Out of range! Must be at: 0-1000\n");
    }
    else if (argc == 4)
    {
        count = atoi(argv[1]);
        period = atoi(argv[2]);
        prcent = atoi(argv[3]);
        if (count > 0 && period >= 0 && period <= 1000
                && prcent > 0 && prcent <= 100)
            beep_mode(count, period, prcent);
        else
            rt_kprintf("Out of range! period Must be at: 0-1000\n prcent Must be at: 0-100\n");
    }
}
MSH_CMD_EXPORT(beep,  little beep);

